using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Xml.Serialization;
using AreaBuilder.Forms;
using Microsoft.Glee.Drawing;
using Microsoft.Glee.GraphViewerGdi;
using Microsoft.Win32;
using Color=Microsoft.Glee.Drawing.Color;

namespace AreaBuilder.Forms {
    public partial class frmMain : Form {
        private readonly AreaHolder ah = new AreaHolder();
        private frmLoading load;

        public frmMain() {
            Init();
        }

        public frmMain(String file) {
            Init();

            try {
                StreamReader reader = File.OpenText(file);
                var xmlSerial = new XmlSerializer(typeof (Area));
                ah.area = (Area) xmlSerial.Deserialize(reader);
                reader.Close();

                MessageBox.Show("Area loaded!", "Done", MessageBoxButtons.OK, MessageBoxIcon.Information);
                overviewToolStripMenuItem_Click(null, null);

// ReSharper disable DoNotCallOverridableMethodsInConstructor
                Text = String.Format("The Burning Eye :: Area Builder [{0}]", ah.area.Title);
// ReSharper restore DoNotCallOverridableMethodsInConstructor

                newToolStripMenuItem.Enabled = false;
                openToolStripMenuItem.Enabled = false;
                saveToolStripMenuItem.Enabled = true;
                saveAsToolStripMenuItem.Enabled = true;
                closeToolStripMenuItem.Enabled = true;
                exportToolStripMenuItem.Enabled = true;
                viewToolStripMenuItem.Enabled = true;
                sectionsToolStripMenuItem.Enabled = true;
                extrasToolStripMenuItem.Enabled = true;

                addNewToolStripMenuItem.Enabled = true;
                addNewToolStripMenuItem1.Enabled = true;
                addNewToolStripMenuItem2.Enabled = true;
                addNewToolStripMenuItem3.Enabled = true;
                addNewToolStripMenuItem4.Enabled = true;
                addNewToolStripMenuItem5.Enabled = true;
                addNewToolStripMenuItem6.Enabled = true;
            } catch (Exception) {
                MessageBox.Show("Something went wrong... are you sure you loaded the right file?", "Whoops!",
                                MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void Init() {
            InitializeComponent();

            foreach (Control c in Controls) {
                if (c is MdiClient) {
                    c.BackColor = BackColor;
                    c.BackgroundImage = BackgroundImage;
                }
            }


            string keyName = "Burning.Eye.Editor";
            string keyValue = "Burning-Eye Area File";
            RegistryKey key = Registry.ClassesRoot.CreateSubKey(keyName);
// ReSharper disable PossibleNullReferenceException
            key.SetValue("", keyValue);
            key = key.CreateSubKey("shell");
            key = key.CreateSubKey("open");
            key = key.CreateSubKey("command");
            key.SetValue("", Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + @"\AreaBuilder.exe %1");

            keyName = ".bea";
            keyValue = "Burning.Eye.Editor";
            key = Registry.ClassesRoot.CreateSubKey(keyName);
            key.SetValue("", keyValue);
// ReSharper restore PossibleNullReferenceException
        }

        private void frmMain_Load(object sender, EventArgs e) {
            CheckForIllegalCrossThreadCalls = false;

            menuStrip.MdiWindowListItem = windowToolStripMenuItem;
        }

        private void popLoading() {
#pragma warning disable 168
            var ia = new ImportArea(openFile.FileName, ah.area);
#pragma warning restore 168

            if (load != null)
                load.Dispose();

            MessageBox.Show("Area loaded!", "Done", MessageBoxButtons.OK, MessageBoxIcon.Information);
            overviewToolStripMenuItem_Click(null, null);

            Text = String.Format("The Burning Eye :: Area Builder [{0}]", ah.area.Title);

            newToolStripMenuItem.Enabled = false;
            openToolStripMenuItem.Enabled = false;
            saveToolStripMenuItem.Enabled = true;
            saveAsToolStripMenuItem.Enabled = true;
            closeToolStripMenuItem.Enabled = true;
            exportToolStripMenuItem.Enabled = true;
            viewToolStripMenuItem.Enabled = true;
            sectionsToolStripMenuItem.Enabled = true;
            extrasToolStripMenuItem.Enabled = true;

            addNewToolStripMenuItem.Enabled = true;
            addNewToolStripMenuItem1.Enabled = true;
            addNewToolStripMenuItem2.Enabled = true;
            addNewToolStripMenuItem3.Enabled = true;
            addNewToolStripMenuItem4.Enabled = true;
            addNewToolStripMenuItem5.Enabled = true;
            addNewToolStripMenuItem6.Enabled = true;
        }

        private void importareToolStripMenuItem_Click(object sender, EventArgs e) {
            openFile.Filter = "Area files (*.are)|*.are";
            openFile.ShowDialog();

            if (!String.IsNullOrEmpty(openFile.FileName)) {
                load = new frmLoading { MdiParent = this };

                ah.area = new Area();
                var thrLoad = new Thread(popLoading);
                thrLoad.Start();

                load.Location = new Point((Size.Width - load.Size.Width)/2 + 40, (Size.Height - load.Size.Height)/2 - 60);
                load.Show();
            } else
                MessageBox.Show("You've got to select an area file to import!", "Whoops!", MessageBoxButtons.OK,
                                MessageBoxIcon.Error);
        }

        private void exportToolStripMenuItem_Click(object sender, EventArgs e) {
            if (String.IsNullOrEmpty(ah.filename))
                saveToolStripMenuItem_Click(null, null);
            if (String.IsNullOrEmpty(ah.filename))
                return;

            folderBrowser.ShowDialog();
            String output = folderBrowser.SelectedPath;
            if (String.IsNullOrEmpty(output))
                return;


            var t = new Transform(ah.filename, Path.Combine(output, ah.area.File));
            t.createArea();

            MessageBox.Show("Area exported to ROM24b format!", "Done", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e) {
            Application.Exit();
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e) {
            openFile.Filter = "Burning Eye Areas|*.bea|XML Files|*.xml";
            openFile.ShowDialog();
            String file = openFile.FileName;

            try {
                StreamReader reader = File.OpenText(file);
                var xmlSerial = new XmlSerializer(typeof (Area));
                ah.area = (Area) xmlSerial.Deserialize(reader);
                reader.Close();

                MessageBox.Show("Area loaded!", "Done", MessageBoxButtons.OK, MessageBoxIcon.Information);
                overviewToolStripMenuItem_Click(null, null);

                Text = String.Format("The Burning Eye :: Area Builder [{0}]", ah.area.Title);

                newToolStripMenuItem.Enabled = false;
                openToolStripMenuItem.Enabled = false;
                saveToolStripMenuItem.Enabled = true;
                saveAsToolStripMenuItem.Enabled = true;
                closeToolStripMenuItem.Enabled = true;
                exportToolStripMenuItem.Enabled = true;
                viewToolStripMenuItem.Enabled = true;
                sectionsToolStripMenuItem.Enabled = true;
                extrasToolStripMenuItem.Enabled = true;

                addNewToolStripMenuItem.Enabled = true;
                addNewToolStripMenuItem1.Enabled = true;
                addNewToolStripMenuItem2.Enabled = true;
                addNewToolStripMenuItem3.Enabled = true;
                addNewToolStripMenuItem4.Enabled = true;
                addNewToolStripMenuItem5.Enabled = true;
                addNewToolStripMenuItem6.Enabled = true;
            } catch (Exception) {
                MessageBox.Show("Something went wrong... are you sure you loaded the right file?", "Whoops!",
                                MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void closeToolStripMenuItem_Click(object sender, EventArgs e) {
            newToolStripMenuItem.Enabled = true;
            openToolStripMenuItem.Enabled = true;
            saveToolStripMenuItem.Enabled = false;
            saveAsToolStripMenuItem.Enabled = false;
            closeToolStripMenuItem.Enabled = false;
            exportToolStripMenuItem.Enabled = false;
            viewToolStripMenuItem.Enabled = false;
            sectionsToolStripMenuItem.Enabled = false;
            extrasToolStripMenuItem.Enabled = false;

            addNewToolStripMenuItem.Enabled = false;
            addNewToolStripMenuItem1.Enabled = false;
            addNewToolStripMenuItem2.Enabled = false;
            addNewToolStripMenuItem3.Enabled = false;
            addNewToolStripMenuItem4.Enabled = false;
            addNewToolStripMenuItem5.Enabled = false;
            addNewToolStripMenuItem6.Enabled = false;

            Text = String.Format("The Burning Eye :: Area Builder [None Loaded]");

            for (int i = 0; i < MdiChildren.Length; i++)
                MdiChildren[i].Dispose();

            ah.area = null;
            ah.filename = "";
        }

        private void overviewToolStripMenuItem_Click(object sender, EventArgs e) {
            var sb = new StringBuilder();
            sb.Append(String.Format("Mobs: {0}", ah.area.Mobs.Count));
            sb.Append(Environment.NewLine);
            sb.Append(String.Format("Mobprogs: {0}", ah.area.Progs.Count));
            sb.Append(Environment.NewLine);
            sb.Append(String.Format("Rooms: {0}", ah.area.Rooms.Count));
            sb.Append(Environment.NewLine);
            sb.Append(String.Format("Items: {0}", ah.area.Items.Count));
            sb.Append(Environment.NewLine);
            sb.Append(String.Format("Shops: {0}", ah.area.Shops.Count));
            sb.Append(Environment.NewLine);
            sb.Append(String.Format("Resets: {0}", ah.area.Resets.Count));
            sb.Append(Environment.NewLine);
            sb.Append(String.Format("Specials: {0}", ah.area.Specials.Count));
            sb.Append(Environment.NewLine);

            MessageBox.Show(sb.ToString(), "Area Overview", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private void areaSettingsToolStripMenuItem_Click(object sender, EventArgs e) {
            var settings = new frmAreaSettings(ah) { MdiParent = this };

            settings.Location = new Point((Size.Width - settings.Size.Width)/2, (Size.Height - settings.Size.Height)/2);
            settings.Show();
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e) {
            if (String.IsNullOrEmpty(ah.filename)) {
                saveFile.ShowDialog();
                ah.filename = saveFile.FileName;

                if (String.IsNullOrEmpty(ah.filename))
                    return;
            }

            if (ah.area == null)
                return;

            StreamWriter writer = File.CreateText(ah.filename);
            var xmlSerial = new XmlSerializer(typeof (Area));

            xmlSerial.Serialize(writer, ah.area);
            writer.Close();
        }

        private void saveAsToolStripMenuItem_Click(object sender, EventArgs e) {
            saveFile.ShowDialog();
            ah.filename = saveFile.FileName;

            if (String.IsNullOrEmpty(ah.filename))
                return;

            saveToolStripMenuItem_Click(null, null);
        }

        private void overviewToolStripMenuItem1_Click(object sender, EventArgs e) {
            // Mobs
            var over = new frmOverview(ah, "mobs") { MdiParent = this };
            over.Location = new Point((Size.Width - over.Size.Width)/2 + 40, (Size.Height - over.Size.Height)/2 - 60);
            over.Show();
        }

        private void overviewToolStripMenuItem2_Click(object sender, EventArgs e) {
            // Helps
            var over = new frmOverview(ah, "helps") { MdiParent = this };
            over.Location = new Point((Size.Width - over.Size.Width)/2 + 40, (Size.Height - over.Size.Height)/2 - 60);
            over.Show();
        }

        private void overviewToolStripMenuItem3_Click(object sender, EventArgs e) {
            // Rooms
            var over = new frmOverview(ah, "rooms") { MdiParent = this };
            over.Location = new Point((Size.Width - over.Size.Width)/2 + 40, (Size.Height - over.Size.Height)/2 - 60);
            over.Show();
        }

        private void overviewToolStripMenuItem4_Click(object sender, EventArgs e) {
            // Items
            var over = new frmOverview(ah, "items") { MdiParent = this };
            over.Location = new Point((Size.Width - over.Size.Width)/2 + 40, (Size.Height - over.Size.Height)/2 - 60);
            over.Show();
        }

        private void overviewToolStripMenuItem5_Click(object sender, EventArgs e) {
            // Mobprogs
            var over = new frmOverview(ah, "progs") { MdiParent = this };
            over.Location = new Point((Size.Width - over.Size.Width)/2 + 40, (Size.Height - over.Size.Height)/2 - 60);
            over.Show();
        }

        private void overviewToolStripMenuItem6_Click(object sender, EventArgs e) {
            // Shops
            var over = new frmOverview(ah, "shops") { MdiParent = this };
            over.Location = new Point((Size.Width - over.Size.Width)/2 + 40, (Size.Height - over.Size.Height)/2 - 60);
            over.Show();
        }

        private void overviewToolStripMenuItem7_Click(object sender, EventArgs e) {
            // Resets
            var over = new frmOverview(ah, "resets") { MdiParent = this };
            over.Location = new Point((Size.Width - over.Size.Width)/2 + 40, (Size.Height - over.Size.Height)/2 - 60);
            over.Show();
        }

        private void overviewToolStripMenuItem8_Click(object sender, EventArgs e) {
            // Specials
            var over = new frmOverview(ah, "specials") { MdiParent = this };
            over.Location = new Point((Size.Width - over.Size.Width)/2 + 40, (Size.Height - over.Size.Height)/2 - 60);
            over.Show();
        }

        private void openAllToolStripMenuItem_Click(object sender, EventArgs e) {
            overviewToolStripMenuItem1_Click(null, null);
            overviewToolStripMenuItem2_Click(null, null);
            overviewToolStripMenuItem3_Click(null, null);
            overviewToolStripMenuItem4_Click(null, null);
            overviewToolStripMenuItem5_Click(null, null);
            overviewToolStripMenuItem6_Click(null, null);
            overviewToolStripMenuItem7_Click(null, null);
            overviewToolStripMenuItem8_Click(null, null);
        }

        private void cascadeToolStripMenuItem_Click(object sender, EventArgs e) {
            LayoutMdi(MdiLayout.Cascade);
        }

        private void tileHorizontallyToolStripMenuItem_Click(object sender, EventArgs e) {
            LayoutMdi(MdiLayout.TileHorizontal);
        }

        private void tileVerticallyToolStripMenuItem_Click(object sender, EventArgs e) {
            LayoutMdi(MdiLayout.TileVertical);
        }

        private void frmMain_FormClosing(object sender, FormClosingEventArgs e) {
            DialogResult dr = MessageBox.Show("Are you sure you want to quit?", "Wait!", MessageBoxButtons.YesNo,
                                              MessageBoxIcon.Question);

            if (dr.Equals(DialogResult.No))
                e.Cancel = true;
        }

        private void newToolStripMenuItem_Click(object sender, EventArgs e) {
            ah.area = new Area();

            Text = String.Format("The Burning Eye :: Area Builder [New Area]");

            newToolStripMenuItem.Enabled = false;
            openToolStripMenuItem.Enabled = false;
            saveToolStripMenuItem.Enabled = true;
            saveAsToolStripMenuItem.Enabled = true;
            closeToolStripMenuItem.Enabled = true;
            exportToolStripMenuItem.Enabled = true;
            viewToolStripMenuItem.Enabled = true;
            sectionsToolStripMenuItem.Enabled = true;
            extrasToolStripMenuItem.Enabled = true;

            addNewToolStripMenuItem.Enabled = true;
            addNewToolStripMenuItem1.Enabled = true;
            addNewToolStripMenuItem2.Enabled = true;
            addNewToolStripMenuItem3.Enabled = true;
            addNewToolStripMenuItem4.Enabled = true;
            addNewToolStripMenuItem5.Enabled = true;
            addNewToolStripMenuItem6.Enabled = true;

            areaSettingsToolStripMenuItem_Click(null, null);
        }

        private void addNewToolStripMenuItem_Click(object sender, EventArgs e) {
            // Mobs

            var mobs = new frmMobs(ah, -1) { MdiParent = this };
            mobs.Location = new Point((Size.Width - mobs.Size.Width)/2 + 40, (Size.Height - mobs.Size.Height)/2 - 60);
            mobs.Show();
        }

        private void addNewToolStripMenuItem1_Click(object sender, EventArgs e) {
            // Helps

            var help = new frmHelp(ah, -1) { MdiParent = this };
            help.Location = new Point((Size.Width - help.Size.Width)/2 + 40, (Size.Height - help.Size.Height)/2 - 60);
            help.Show();
        }

        private void addNewToolStripMenuItem2_Click(object sender, EventArgs e) {
            // Rooms

            var room = new frmRoom(ah, -1) { MdiParent = this };
            room.Location = new Point((Size.Width - room.Size.Width)/2 + 40, (Size.Height - room.Size.Height)/2 - 60);
            room.Show();
        }

        private void addNewToolStripMenuItem3_Click(object sender, EventArgs e) {
            // Items

            var item = new frmObjects(ah, -1) { MdiParent = this };
            item.Location = new Point((Size.Width - item.Size.Width)/2 + 40, (Size.Height - item.Size.Height)/2 - 60);
            item.Show();
        }

        private void addNewToolStripMenuItem4_Click(object sender, EventArgs e) {
            // Progs

            var prog = new frmProg(ah, -1) { MdiParent = this };
            prog.Location = new Point((Size.Width - prog.Size.Width)/2 + 40, (Size.Height - prog.Size.Height)/2 - 60);
            prog.Show();
        }

        private void addNewToolStripMenuItem5_Click(object sender, EventArgs e) {
            // Shops

            var shop = new frmShops(ah, -1) { MdiParent = this };
            shop.Location = new Point((Size.Width - shop.Size.Width)/2 + 40, (Size.Height - shop.Size.Height)/2 - 60);
            shop.Show();
        }

        private void addNewToolStripMenuItem6_Click(object sender, EventArgs e) {
            // Resets

            var reset = new frmResets(ah, -1) { MdiParent = this };
            reset.Location = new Point((Size.Width - reset.Size.Width)/2 + 40, (Size.Height - reset.Size.Height)/2 - 60);
            reset.Show();
        }

        private Room getRoom(int vnum) {
            for (int i = 0; i < ah.area.Rooms.Count; i++) {
                var r = (Room) ah.area.Rooms[i];

                if (vnum == r.VNum)
                    return r;
            }

            return null;
        }

        private static String getDir(int dir) {
            switch (dir) {
                case 0:
                    return "north";
                case 1:
                    return "east";
                case 2:
                    return "south";
                case 3:
                    return "west";
                case 4:
                    return "up";
                case 5:
                    return "down";
            }

            return "";
        }

        private void drawAreaToolStripMenuItem_Click(object sender, EventArgs e) {
            folderBrowser.ShowDialog();
            String output = folderBrowser.SelectedPath;
            String startRoom = "";
            String destRoom;
            Node n;
            var graph = new Graph(ah.area.Title);

            if (String.IsNullOrEmpty(output))
                return;

            graph.GraphAttr.Backgroundcolor = Color.PowderBlue;
            graph.GraphAttr.FontName = "Verdana";

            for (int i = 0; i < ah.area.Rooms.Count; i++) {
                var r = (Room) ah.area.Rooms[i];

                if (i == 0) {
                    startRoom = String.Format("#{0} - {1}", r.VNum, r.Title);
                    n = (Node) graph.AddNode(startRoom);
                    n.NodeAttribute.Fillcolor = Color.RoyalBlue;
                }

                for (int j = 0; j < r.Exits.Count; j++) {
                    var t = (RoomExit) r.Exits[j];
                    Room dest = getRoom(t.LinkVNum);
                    if (dest == null)
                        continue;

                    destRoom = String.Format("#{0} - {1}", dest.VNum, dest.Title);

                    n = (Node) graph.AddNode(destRoom);
                    if (!destRoom.Equals(startRoom))
                        n.NodeAttribute.Fillcolor = Color.MistyRose;

                    var edge =
                        (Edge)
                        graph.AddEdge(String.Format("#{0} - {1}", r.VNum, r.Title),
                                      String.Format("#{0} - {1}", dest.VNum, dest.Title));

                    edge.Attr.ArrowHeadAtTarget = ArrowStyle.Normal;
                    edge.Attr.LineWidth = 2;
                    edge.Attr.Label = getDir(t.Direction);
                }
            }

            var renderer = new GraphRenderer(graph);

            renderer.CalculateLayout();

            var bitmap = new Bitmap((int) graph.Width, (int) graph.Height, PixelFormat.Format32bppPArgb);
            renderer.Render(bitmap);

            bitmap.Save(String.Format("{0}.png", Path.Combine(output, ah.area.Title)));

            MessageBox.Show("Area layout written to disk!", "Yay", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private void reportToolStripMenuItem_Click(object sender, EventArgs e) {
            var iReport = new ItemReport(ah.area.Title);

            IOrderedEnumerable<Item> query = from Item i in ah.area.Items
                                             orderby i.Keywords ascending
                                             select i;

            foreach (Item i in query)
                iReport.AddItem(i);

            iReport.Render();

            MessageBox.Show("Your report has been written to disk!", "Yay!", MessageBoxButtons.OK,
                            MessageBoxIcon.Information);

            Process.Start(String.Format(@"""{0}\{1}""", Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), String.Format("{0}.html", ah.area.Title)));
        }
    }
}